package LeetDev.a3d;

import java.io.DataInputStream;
import java.io.IOException;
import java.util.Vector;

import javax.microedition.khronos.opengles.GL10;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLUtils;

public class Texture {
	public static Vector<Texture> s_globalTextures=new Vector<Texture>();
	public static String s_texturePath;
	
	private String m_mapName;
	private float m_strength;
	private int m_filter,m_mask;
	private boolean m_containsAlpha;
	private int m_width, m_height;
	private boolean m_compiled;
	private int[] m_handle;

	private int m_ref;

	public Texture(FileInput fin,int mask) throws Exception
	{
		m_compiled=false;
		m_containsAlpha=false;
		m_mask=mask;
		m_ref=1;
		m_mapName=fin.popString();
		m_strength=fin.popFloat();
		m_filter=fin.popInt();
		m_mapName=s_texturePath+m_mapName;
		m_handle=new int[1];
		m_handle[0]=0;
	}

	public void destruct(GL10 gl)
	{
		if(m_handle[0]==0)
		{
			gl.glDeleteTextures(1, m_handle, 0);
		}
	}

	public boolean haveAlpha()
	{
		return(m_containsAlpha);
	}
	
	public boolean isSame(final Texture other)
	{
		if(m_mapName==other.m_mapName&&
			m_filter==other.m_filter&&
			m_mask==other.m_mask&&
			m_containsAlpha==other.m_containsAlpha&&
			m_width==other.m_width&&
			m_height==other.m_height)
		{
			return(true);
		}
		return(false);
	}

	public float GetStrength()
	{
		return(m_strength);
	}
	public String GetMapName()
	{
		return(m_mapName);
	}
	
	public void compile(GL10 gl) throws Exception
	{
		if(m_compiled) {return;}
		m_compiled=true;
		
		if(m_handle[0]==0)
		{
			gl.glGenTextures(1, m_handle, 0);
		}
		DataInputStream is=new DataInputStream(getClass().getResourceAsStream(m_mapName));

		Bitmap surface=BitmapFactory.decodeStream(is);
		m_width=surface.getWidth();
		m_height=surface.getHeight();
		m_containsAlpha=false;
		
		int max[]=new int[1];
		gl.glGetIntegerv(GL10.GL_MAX_TEXTURE_SIZE,max,0);
		if(max[0]<m_width || max[0]<m_height)
		{
			throw new IOException("The image: "+m_mapName+" is larger than the hardware supports.");
		}
		
		int sizex,sizey;
		sizex=sizey=1;
		while(sizex<m_width) {sizex+=sizex;}
		while(sizey<m_height) {sizey+=sizey;}
		if(sizex!=m_width||sizey!=m_height)
		{
			throw new IOException("The image: "+m_mapName+" is not a square two potent size.");
		}
		m_containsAlpha=surface.hasAlpha();
		
		gl.glBindTexture(GL10.GL_TEXTURE_2D,m_handle[0]);
		if(m_containsAlpha)
		{
			GLUtils.texImage2D(GL10.GL_TEXTURE_2D,0,GL10.GL_RGBA,surface,0);
		}
		else
		{
			GLUtils.texImage2D(GL10.GL_TEXTURE_2D,0,GL10.GL_RGB,surface,0);
		}
	}

	/*
		Can we optimize this by just setting the changes from the previous texture?
		We could probably do this on a model basis if the draw order within the model doesn't change...
		Check this after reaching feature freeze.
	*/
	public void use(GL10 gl,int order)
	{
		if(order!=0)
		{
			return;	// OpenGL ES 1.0 do not support multitexture
		}
		gl.glActiveTexture(GL10.GL_TEXTURE0);
		gl.glEnable(GL10.GL_TEXTURE_2D);
		gl.glBindTexture(GL10.GL_TEXTURE_2D,m_handle[0]);
		if((m_filter&0x1)!=0)
		{
			gl.glTexParameterx(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MAG_FILTER,GL10.GL_LINEAR);
		}
		else
		{
			gl.glTexParameterx(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MAG_FILTER,GL10.GL_NEAREST);
		}
		gl.glTexParameterx(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_LINEAR_MIPMAP_LINEAR);
		/*
		if((m_mask&0x2)!=0)
		{
			gl.glTexGeni(GL10.GL_S,GL_TEXTURE_GEN_MODE,GL10.GL_SPHERE_MAP);
			gl.glTexGeni(GL10.GL_T,GL_TEXTURE_GEN_MODE,GL10.GL_SPHERE_MAP);
			gl.glEnable(GL10.GL_TEXTURE_GEN_S);
			gl.glEnable(GL10.GL_TEXTURE_GEN_T);
			gl.glTexEnvf (GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_COMBINE);
			gl.glTexEnvf (GL10.GL_TEXTURE_ENV, GL10.GL_COMBINE_RGB, GL10.GL_ADD);
		}
		else
		{
			gl.glDisable(GL10.GL_TEXTURE_GEN_S);
			gl.glDisable(GL10.GL_TEXTURE_GEN_T);
			gl.glTexEnvf (GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_COMBINE_EXT);
			gl.glTexEnvf (GL10.GL_TEXTURE_ENV, GL10.GL_COMBINE_RGB_EXT, GL10.GL_MODULATE);
		}
		*/
		gl.glTexParameterx(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_WRAP_S, (m_filter&0x2)!=0?GL10.GL_CLAMP_TO_EDGE:GL10.GL_REPEAT);
		gl.glTexParameterx(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_WRAP_T, (m_filter&0x4)!=0?GL10.GL_CLAMP_TO_EDGE:GL10.GL_REPEAT);
	}

	public void addRef()
	{
		m_ref++;
	}

	public boolean subRef()
	{
		m_ref--;
		boolean exists=(m_ref>0)?true:false;

		if(!exists)
		{
			s_globalTextures.removeElement(this);
		}
		return(exists);
	}

}
